<html>
    <head>
        <title>DTO 导言</title>
    </head>
    <body>
        <script>
             // 数据传输对象 Dto  

                    /*

                        一、导言

                                    数据传输对象（DTO）用于在"应用层"和"表示层"或 "其他类型的客户端" 之间传输数据。

                                    通常，使用DTO(输入Dto)作为参数"从表示层"（可选）调用 "应用程序服务"。

                                    "应用服务层"使用领域对象执行一些特定的业务逻辑并（可选）将DTO(输出Dto)返回给表示层。

                                    因此，表示层与域层完全隔离。


                                    1、为什么需要Dto？

                                            如果你认为你知道并确认使用DTO的好处，你可以跳过本节。

                                            （1）、领域对象的抽象

                                                        DTO提供了一种从表示层中抽象域对象的有效方法。

                                                        实际上，你的层是正确分离的。如果你想完全更改表示层，你可以继续使用现有的应用程序层和域层。

                                                        或者，你可以重新编写你的领域层，完全更改数据库模式、实体和O/RM框架，所有这些都 "无需更改表示层".

                                                        当然，只要你的应用程序服务的契约（方法签名和DTO）保持不变
                                                        
                                            (2)、数据隐藏

                                                        假设你有一个User实体，属性为Id、Name、EmailAddress和Password。

                                                        如果UserAppService的GetAllUsers()方法返回一个List<User>，

                                                        任何人都可以访问你所有用户的密码，即使你没有在屏幕上显示它。

                                                        这不仅仅是关于安全性，而是关于数据隐藏。用程序服务应该只返回表示层（或客户端）需要的内容。不多不少。

                                            (3)、序列化和延迟加载问题

                                                        当你将数据（对象）返回到表示层时，它很可能是序列化的。

                                                        例如，在返回JSON的REST API中，你的对象将被序列化为JSON并发送到客户端。

                                                        在这方面，将实体返回到表示层可能会有问题，特别是如果你使用关系数据库和像实体框架核心这样的ORM提供程序。怎么做？

                                                        在现实世界的应用程序中，你的实体可能具有对彼此的引用。User实体可以引用它的Roles。如果你想序列化User，它的Roles也会序列化。

                                                        Role类可能有一个List<Permission>，Permission类可以引用PermissionGroup类等等……想象一下所有这些对象都被同时序列化。

                                                        你可能很容易意外地序列化你的整个数据库！此外，如果你的对象有循环引用，它们可能根本不会被序列化。

                                                        解决方案是什么？将属性标记为NonSerialized？

                                                        不，你无法知道何时应该序列化，何时不应该序列化。在一种应用程序服务方法中可能需要它，而在另一种应用程序服务方法中不需要它。

                                                        在这种情况下，返回安全、可序列化和专门设计的DTO是一个不错的选择。



                                                        几乎所有的O/RM框架都支持延迟加载。这是一个在需要时从数据库中加载实体的功能。

                                                        假设一个User类引用了一个Role类。当你从数据库中获得一个User时，Role属性（或集合）没有被填充。

                                                        当你第一次读取Role属性时，它是从数据库中加载的。
                                                        
                                                        因此，如果你将这样一个实体返回到表示层，它将导致它通过执行额外的查询从数据库中检索额外的实体。

                                                        如果序列化工具读取实体，它会递归地读取所有属性，并且可以再次检索你的整个数据库（如果实体之间存在关系）。


                                                        如果你在表示层中使用实体，可能会出现更多问题。最好不要在表示层中引用域/业务层程序集。

                                                        如果你确信使用DTO，我们可以继续ABP提供的关于DTO的建议。
                    */ 
        </script>
    </body>
</html>